﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using PloobsEngine;

namespace Etapa1.ModelDescription.ModelSamples
{
    public class TerrainModel
    {
        Texture2D texture;
        float[] alturas;
        int _numVertsPerRow;
        int _numVertsPerCol;
        int _cellSpacing;
        int _numCellsPerRow;
        int _numCellsPerCol;
        int _width;
        int _depth;        
        float _heightScale = 50;

        private float sampleHeightFilter3x3(int i, int j, float[] alParcial)
        {
              float avg = 0.0f;
              float num = 0.0f;

              for(int m = i-1; m <= i+1; ++m)
              {
                    for(int n = j-1; n <= j+1; ++n)
                    {
                          if( inBounds(m,n) )
                          {
                                avg += alParcial[m * _numVertsPerCol + n];
                                num += 1.0f;
                          }
                    }
              }

              return avg / num;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="i">linha</param>
        /// <param name="j">coluna</param>
        /// <returns></returns>
        bool inBounds(int i, int j)
        {
            if (i < 0 || i >= _numVertsPerRow || j < 0 || j >= _numVertsPerCol)
                return false;
            return true;
        }   

        public TerrainModel(String textureName, int cellSpacing)
        {
            texture = EngineStuff.CustomContentManager.GetAsset<Texture2D>(textureName);

            this._numVertsPerRow = texture.Width;
            this._numVertsPerCol = texture.Height;
            int myWidth  = texture.Width;
            int myHeight = texture.Height;
            float[] alParcial = new float[myWidth * myHeight];
            alturas = new float[myWidth * myHeight];

            Color[] cores= new Color[myWidth * myHeight];
            texture.GetData<Color>(cores);

            for (int j = 0; j < myWidth * myHeight; j++)
            {
                alParcial[j] = cores[j].ToVector3().X;
            }

            for (int ii = 0; ii < myHeight; ii++)
			{
			    for (int j = 0; j < myWidth; j++)
			    {
                    alturas[ii*_numVertsPerRow  +   j] = sampleHeightFilter3x3(ii, j, alParcial) * _heightScale;            
			    }
			}

            

            this._cellSpacing = cellSpacing;
            
            _numCellsPerRow = _numVertsPerRow - 1;
            _numCellsPerCol = _numVertsPerCol - 1;
            _width = _numCellsPerRow * _cellSpacing;
            _depth = _numCellsPerCol * _cellSpacing;
            vertexCount = _numVertsPerRow * _numVertsPerCol;
            primitiveCount = _numCellsPerRow * _numCellsPerCol * 2;
                        
            int startX = -_width / 2;
            int startZ = _depth / 2;            
            int endX = _width / 2;
            int endZ = -_depth / 2;
            
            float uCoordIncrementSize = 1.0f / (float)_numCellsPerRow;
            float vCoordIncrementSize = 1.0f / (float)_numCellsPerCol;            
            VertexPositionNormalTexture[] myVertices = new VertexPositionNormalTexture[myWidth * myHeight];
            
            int i = 0;
            for (int z = startZ; z >= endZ; z -= _cellSpacing)
            {
                int j = 0;
                for (int x = startX; x <= endX; x += _cellSpacing)
                {                    
                    int index = i * _numVertsPerRow + j;
                    VertexPositionNormalTexture vpnt =  new VertexPositionNormalTexture();
                    vpnt.Normal = Vector3.Up;                    
                    vpnt.Position = new Vector3(x, alturas[index] , z);
                    vpnt.TextureCoordinate = new Vector2(j * uCoordIncrementSize, i * vCoordIncrementSize);
                    myVertices[index] = vpnt;
                    j++;
                }
                i++; 
            }

            
            vertexBuffer = new VertexBuffer(EngineStuff.GraphicsDevice, VertexPositionNormalTexture.SizeInBytes * myWidth * myHeight, BufferUsage.None);
            vertexBuffer.SetData(myVertices);

            int[] terrainIndices = new int[_numCellsPerCol * _numCellsPerRow * 6];
            //int baseIndex = 0;            
            for (int j = 0; j < _numCellsPerCol; j++)
            {
                for (i = 0; i < _numCellsPerRow; i++)
                {                    
                    terrainIndices[(j + i * (_numVertsPerRow - 1)) * 6] = (j + i * _numVertsPerRow); 
                    terrainIndices[(j + i * (_numVertsPerRow - 1)) * 6 + 1] = ((j + 1) + i * _numVertsPerRow);
                    terrainIndices[(j + i * (_numVertsPerRow - 1)) * 6 + 2] = ((j + 1) + (i + 1) * _numVertsPerRow);

                    terrainIndices[(j + i * (_numVertsPerRow - 1)) * 6 + 3] = (j + (i + 1) * _numVertsPerRow);
                    terrainIndices[(j + i * (_numVertsPerRow - 1)) * 6 + 4] = (j + i * _numVertsPerRow);
                    terrainIndices[(j + i * (_numVertsPerRow - 1)) * 6 + 5] = ((j + 1) + (i + 1) * _numVertsPerRow);
                }
            }
            indexBuffer = new IndexBuffer(EngineStuff.GraphicsDevice, typeof(int), _numCellsPerCol * _numCellsPerRow * 6, BufferUsage.None);
            indexBuffer.SetData(terrainIndices);

            vertexDeclaration = new VertexDeclaration(EngineStuff.GraphicsDevice, VertexPositionNormalTexture.VertexElements);

            //primitiveCount = terrainIndices.Count() / 3;
            //vertexCount = myWidth * myHeight;
        }

        public VertexBuffer vertexBuffer;
        public IndexBuffer indexBuffer;
        public VertexDeclaration vertexDeclaration;
        public int vertexCount;
        public int primitiveCount;

    }
}
